#pragma once
#include "Compatible.h"
#include "FileIO_Pkg.h"
#include "Useful_Pkg.h"

/**
 * 这个类实现了异步读写 ini 文件。
 * 其 Get 和 Set 操作都是在内存进行的，
 * 只有调用 Load 和 Store 时才会触发 IO。
 * 不会检查 ini 文件的语法。
 * 由于 map 容器的特性，
 * 将会自动排序节和键值。
 *
 * 例子:
 *
 * Config config("test.ini");
 * config.Load();
 * config.Get("user","name","");
 * config.Set("user","name","value");
 * config.Store();
 *
 * 如果以 bool 的形式获取值，
 * 将会自动识别并转换 false 和 0 值。
 * 例如:
 *
 * [user]
 * name=0
 *
 * Get("user","name",false) 返回 false
 *
 * [user]
 * name=123
 *
 * Get("user","name",false) 返回 true
 *
 * [user]
 * name=true
 *
 * Get("user","name",false) 返回 true
 */
class Config {
public:
    Config();

    /**
     * 映射到文件
     *
     * @param file 文件
     */
    Config(const std::string& file);

    /*
     * 从文件加载
     *
     * @return 如果加载失败，则返回 false
     */
    bool Load();

    /**
     * 从文本加载
     *
     * @param text ini 格式文本
     * @return 如果加载失败，则返回 false
     */
    bool Load(std::string text);

    /**
     * 储存到文件
     *
     * @return 如果储存失败，则返回 false
     */
    bool Store();

    /**
     * 储存到文本
     *
     * @return ini 格式文本
     */
    std::string StoreString() {
        std::string result;
        for (const auto& i : table) {
            result += "[" + i.first + "]\n";
            for (const auto& n : i.second) {
                result += n.first + "=" + n.second + "\n";
            }
        }
        return result;
    }

    template<typename _Class>
	struct value {
		value(const std::string &val) noexcept
			: pop(nullptr)
			, buf(val) {}
		value(const char *val) noexcept
			: pop(nullptr)
			, buf(val) {
		}
		value(_Class val)
			: buf("") {
			this->pop = new _Class(val);
		}
		operator int() {
			if (this->pop == nullptr)
				return std::stoi(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator double() {
			if (this->pop == nullptr)
				return std::stod(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator float() {
			if (this->pop == nullptr)
				return std::stof(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator long double() {
			if (this->pop == nullptr)
				return std::stold(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator std::string() {
			if (this->pop == nullptr)
				return this->buf;
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator std::wstring() {
			if (this->pop == nullptr)
				return std::wstring(this->buf.begin(), this->buf.end());
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator bool() {
			if (this->pop == nullptr)
				return atob(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator long long() {
			if (this->pop == nullptr)
				return std::atoll(this->buf.c_str());
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator const char *() {
			if (this->pop == nullptr)
				return this->buf.c_str();
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator unsigned long() {
			if (this->pop == nullptr)
				return std::stoul(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}
		operator unsigned long long() {
			if (this->pop == nullptr)
				return std::stoull(this->buf);
			_Class ret = *pop;
			delete pop;
			return ret;
		}

	private:
		void *pop;
		const std::string &buf;
	};

	/**
   * 获取值
   *
   * @param subsection 节
   * @param key 键
   * @param defaultValue 默认值
   * @return 如果节或键不存在，则返回 defaultValue
   */
	template<typename _T = std::string>
	_T Get(const std::string &subsection,
				  const std::string &key,
				  const _T &defaultValue = "") {
		if (subsection == "" || key == "") {
			return "";
		}
		auto i = table.find(subsection);
		if (i != table.end()) {
			auto t = i->second.find(key);
			if (t != i->second.end()) {
				return value(t->second);
			}
		}
		return value(defaultValue);
	}

    /**
     * 设置值
     *
     * @param subsection 节
     * @param key 键
     * @param value 值
     * @return 如果设置失败，则返回 false
     */
    bool Set(const std::string& subsection, const std::string& key,
        const std::string& value) {
        if (subsection == "" || key == "") {
            return false;
        }
        table.emplace(subsection, std::map<std::string, std::string>())
            .first->second[key] = value;
        return true;
    }

    /**
     * 设置值
     *
     * @param subsection 节
     * @param key 键
     * @param value 值
     * @return 如果设置失败，则返回 false
     */
    bool Set(const std::string& subsection, const std::string& key, bool value) {
        if (subsection == "" || key == "") {
            return false;
        }
        table.emplace(subsection, std::map<std::string, std::string>())
            .first->second[key] = value ? "true" : "false";
        return true;
    }

    /**
     * 设置值
     *
     * @param subsection 节
     * @param key 键
     * @param value 值
     * @return 如果设置失败，则返回 false
     */
    bool Set(const std::string& subsection, const std::string& key, int value) {
        if (subsection == "" || key == "") {
            return false;
        }
        table.emplace(subsection, std::map<std::string, std::string>())
            .first->second[key] = std::to_string(value);
        return true;
    }

    /**
     * 设置值
     *
     * @param subsection 节
     * @param key 键
     * @param value 值
     * @return 如果设置失败，则返回 false
     */
    bool Set(const std::string& subsection, const std::string& key,
        long long value) {
        if (subsection == "" || key == "") {
            return false;
        }
        table.emplace(subsection, std::map<std::string, std::string>())
            .first->second[key] = std::to_string(value);
        return true;
    }

private:
    // 文件
    std::string file;

    // <节,<键,值>>
    std::map<std::string, std::map<std::string, std::string>> table;
};